/* Title: Tic-Tac-Toe Game Created: October 5, 2008 Last Edited: October 11, 2008 Author: Blmaster Changes: See Below... */ import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.io.*; import java.util.*; public class TicTacToe implements ActionListener { final String VERSION = "2.0"; //Setting up ALL the variables JFrame window = new JFrame("Tic-Tac-Toe " + VERSION); JMenuBar mnuMain = new JMenuBar(); JMenuItem mnuNewGame = new JMenuItem("New Game"), mnuInstruction = new JMenuItem("Instructions"), mnuExit = new JMenuItem("Exit"), mnuAbout = new JMenuItem("About"); JButton btn1v1 = new JButton("Player vs Player"), btn1vCPU = new JButton("Player vs Computer"), btnQuit = new JButton("Quit"), btnSetName = new JButton("Set Player Names"), btnContinue = new JButton("Continue..."), btnTryAgain = new JButton("Try Again?"); JButton btnEmpty[] = new JButton[10]; JPanel pnlNewGame = new JPanel(), pnlMenu = new JPanel(), pnlMain = new JPanel(), pnlTop = new JPanel(), pnlBottom = new JPanel(), pnlQuitNTryAgain = new JPanel(), pnlPlayingField = new JPanel(); JLabel lblTitle = new JLabel("Tic-Tac-Toe"), lblTurn = new JLabel(), lblStatus = new JLabel("", JLabel.CENTER); JTextArea txtMessage = new JTextArea(); final int winCombo[][] = new int[][] { {1, 2, 3}, {1, 4, 7}, {1, 5, 9}, {4, 5, 6}, {2, 5, 8}, {3, 5, 7}, {7, 8, 9}, {3, 6, 9} /*Horizontal Wins*/ /*Vertical Wins*/ /*Diagonal Wins*/ }; final int X = 535, Y = 342, mainColorR = 190, mainColorG = 50, mainColorB = 50, btnColorR = 70, btnColorG = 70, btnColorB = 70; Color clrBtnWonColor = new Color(190, 190, 190); int turn = 1, player1Won = 0, player2Won = 0, wonNumber1 = 1, wonNumber2 = 1, wonNumber3 = 1; int option; boolean inGame = false; boolean win = false; boolean btnEmptyClicked = false; String message, whoTurn, Player1 = "Player 1", Player2 = "Player 2"; public TicTacToe() { //Setting game properties and layout and sytle... //Setting window properties: window.setSize(X, Y); window.setLocation(350, 260); window.setResizable(false); window.setLayout(new BorderLayout()); window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Setting Menu, Main, Top, Bottom Panel Layout/Backgrounds pnlMenu.setLayout(new FlowLayout(FlowLayout.CENTER)); pnlTop.setLayout(new FlowLayout(FlowLayout.CENTER)); pnlBottom.setLayout(new FlowLayout(FlowLayout.CENTER)); pnlNewGame.setBackground(new Color(mainColorR - 50, mainColorG - 50, mainColorB- 50)); pnlMenu.setBackground(new Color((mainColorR - 50), (mainColorG - 50), (mainColorB- 50))); pnlMain.setBackground(new Color(mainColorR, mainColorG, mainColorB)); pnlTop.setBackground(new Color(mainColorR, mainColorG, mainColorB)); pnlBottom.setBackground(new Color(mainColorR, mainColorG, mainColorB)); //Setting up Panel QuitNTryAgain pnlQuitNTryAgain.setLayout(new GridLayout(1, 2, 2, 2)); pnlQuitNTryAgain.add(btnTryAgain); pnlQuitNTryAgain.add(btnQuit); //Adding menu items to menu bar mnuMain.add(mnuNewGame); mnuMain.add(mnuInstruction); mnuMain.add(mnuAbout); mnuMain.add(mnuExit);// Menu Bar is Complete //Adding buttons to NewGame panel pnlNewGame.setLayout(new GridLayout(4, 1, 2, 10)); pnlNewGame.add(btnContinue); pnlNewGame.add(btn1v1); pnlNewGame.add(btn1vCPU); pnlNewGame.add(btnSetName); //Setting Button propertied btnTryAgain.setEnabled(false); btnContinue.setEnabled(false); //Setting txtMessage Properties txtMessage.setBackground(new Color(mainColorR-30, mainColorG-30, mainColorB-30)); txtMessage.setForeground(Color.white); txtMessage.setEditable(false); //Adding Action Listener to all the Buttons and Menu Items mnuNewGame.addActionListener(this); mnuExit.addActionListener(this); mnuInstruction.addActionListener(this); mnuAbout.addActionListener(this); btn1v1.addActionListener(this); btn1vCPU.addActionListener(this); btnQuit.addActionListener(this); btnSetName.addActionListener(this); btnContinue.addActionListener(this); btnTryAgain.addActionListener(this); //Setting up the playing field pnlPlayingField.setLayout(new GridLayout(3, 3, 2, 2)); pnlPlayingField.setBackground(Color.black); for(int i=1; i<=9; i++) { btnEmpty[i] = new JButton(); btnEmpty[i].setBackground(new Color(btnColorR, btnColorG, btnColorB)); btnEmpty[i].addActionListener(this); pnlPlayingField.add(btnEmpty[i]);// Playing Field is Compelte } //Adding everything needed to pnlMenu and pnlMain pnlMenu.add(mnuMain); pnlMain.add(lblTitle); //Adding to window and Showing window window.add(pnlMenu, BorderLayout.NORTH); window.add(pnlMain, BorderLayout.CENTER); window.setVisible(true); } public static void main(String[] args) { new TicTacToe();// Calling the cl*** construtor. // PROGRAM STARTS HERE! } /* ------------------------- Start of all METHODS. | ------------------------- */ public void showGame() { // Shows the Playing Field // *IMPORTANT*- Does not start out brand new (meaning just shows what it had before) clearPanelSouth(); pnlMain.setLayout(new BorderLayout()); pnlTop.setLayout(new BorderLayout()); pnlBottom.setLayout(new BorderLayout()); pnlTop.add(pnlPlayingField); pnlBottom.add(lblTurn, BorderLayout.WEST); pnlBottom.add(lblStatus, BorderLayout.CENTER); pnlBottom.add(pnlQuitNTryAgain, BorderLayout.EAST); pnlMain.add(pnlTop, BorderLayout.CENTER); pnlMain.add(pnlBottom, BorderLayout.SOUTH); pnlPlayingField.requestFocus(); inGame = true; checkTurn(); checkWinStatus(); } //----------------------------------------------------------------------------------------------------------------------------------- public void new1v1Game() { // Sets all the game required variables to default // and then shows the playing field. // (Basically: Starts a new 1v1 Game) btnEmpty[wonNumber1].setBackground(new Color(btnColorR, btnColorG, btnColorB)); btnEmpty[wonNumber2].setBackground(new Color(btnColorR, btnColorG, btnColorB)); btnEmpty[wonNumber3].setBackground(new Color(btnColorR, btnColorG, btnColorB)); for(int i=1; i<10; i++) { btnEmpty[i].setText(""); btnEmpty[i].setEnabled(true); } turn = 1; win = false; showGame(); } //----------------------------------------------------------------------------------------------------------------------------------- public void goBack() { clearPanelSouth(); pnlMain.setLayout(new FlowLayout(FlowLayout.CENTER)); pnlMain.add(lblTitle); } //----------------------------------------------------------------------------------------------------------------------------------- public void checkWin() { // checks if there are 3 symbols in a row vertically, diagonally, or horizontally. // then shows a message and disables buttons. If the game is over then it asks // if you want to play again. for(int i=0; i<8; i++) { if( !btnEmpty[winCombo[i][0]].getText().equals("") && btnEmpty[winCombo[i][0]].getText().equals(btnEmpty[winCombo[i][1]].getText()) && // if {1 == 2 && 2 == 3} btnEmpty[winCombo[i][1]].getText().equals(btnEmpty[winCombo[i][2]].getText())) { /* The way this checks the if someone won is: First: it checks if the btnEmpty[x] is not equal to an empty string- x being the array number inside the multi-dementional array winCombo[checks inside each of the 7 sets][the first number] Secong: it checks if btnEmpty[x] is equal to btnEmpty[y]- x being winCombo[each set][the first number] y being winCombo[each set the same as x][the second number] (So basically checks if the first and second number in each set is equal to each other) Third: it checks if btnEmtpy[y] is eual to btnEmpty[z]- y being the same y as last time and z being winCombo[each set as y][the third number] Conclusion: So basically it checks if it is equal to the btnEmpty is equal to each set of numbers */ win = true; wonNumber1 = winCombo[i][0]; wonNumber2 = winCombo[i][1]; wonNumber3 = winCombo[i][2]; btnEmpty[wonNumber1].setBackground(clrBtnWonColor); btnEmpty[wonNumber2].setBackground(clrBtnWonColor); btnEmpty[wonNumber3].setBackground(clrBtnWonColor); break; } } if(win || (!win && turn>9)) { if(win) { if(turn % 2 == 0) { message = Player1 + " has won"; player1Won++; } else { message = Player2 + " has won"; player2Won++; } win = false; } else if(!win && turn>9) message = "Both players have tied!\nBetter luck next time."; showMessage(message); for(int i=1; i<=9; i++) { btnEmpty[i].setEnabled(false); } btnTryAgain.setEnabled(true); checkWinStatus(); } else checkTurn(); } //----------------------------------------------------------------------------------------------------------------------------------- public void checkTurn() { if(!(turn % 2 == 0)) { whoTurn = Player1 + " [X]"; } else { whoTurn = Player2 + " [O]"; } lblTurn.setText("Turn: " + whoTurn); } //----------------------------------------------------------------------------------------------------------------------------------- public void checkWinStatus() { lblStatus.setText(Player1 + ": " + player1Won + " | " + Player2 + ": " + player2Won); } //----------------------------------------------------------------------------------------------------------------------------------- public void askUserForPlayerNames() { String temp = Player2; temp = getInput("Enter player 1 name:", Player1); if(temp == null) {/*Do Nothing*/} else if(temp.equals("")) showMessage("Invalid Name!"); else if(temp.equals(Player2)) { option = askMessage("Player 1 name matches Player 2's\nDo you want to continue?", "Name Match", JOptionPane.YES_NO_OPTION); if(option == JOptionPane.YES_OPTION) Player1 = temp; } else if(temp != null) { Player1 = temp; } temp = getInput("Enter player 2 name:", Player2); if(temp == null) {/*Do Nothing*/} else if(temp.equals("")) showMessage("Invalid Name!"); else if(temp.equals(Player1)) { option = askMessage("Player 2 name matches Player 1's\nDo you want to continue?", "Name Match", JOptionPane.YES_NO_OPTION); if(option == JOptionPane.YES_OPTION) Player2 = temp; } else if(temp != null) { Player2 = temp; } } //----------------------------------------------------------------------------------------------------------------------------------- public void setDefaultLayout() { pnlMain.setLayout(new GridLayout(2, 1, 2, 5)); pnlTop.setLayout(new FlowLayout(FlowLayout.CENTER)); pnlBottom.setLayout(new FlowLayout(FlowLayout.CENTER)); } //----------------------------------------------------------------------------------------------------------------------------------- public int askMessage(String message, String title, int option) { return JOptionPane.showConfirmDialog(null, message, title, option); } //----------------------------------------------------------------------------------------------------------------------------------- public String getInput(String message, String setText) { return JOptionPane.showInputDialog(null, message, setText); } //----------------------------------------------------------------------------------------------------------------------------------- public void showMessage(String message) { JOptionPane.showMessageDialog(null, message); } //----------------------------------------------------------------------------------------------------------------------------------- public void clearPanelSouth() { //Removes all the possible panels //that pnlMain, pnlTop, pnlBottom //could have. pnlMain.remove(lblTitle); pnlMain.remove(pnlTop); pnlMain.remove(pnlBottom); pnlTop.remove(pnlNewGame); pnlTop.remove(txtMessage); pnlTop.remove(pnlPlayingField); pnlBottom.remove(lblTurn); pnlBottom.remove(pnlQuitNTryAgain); } /* ------------------------------------- End of all non-Abstract METHODS. | ------------------------------------- */ //-------------------ACTION PERFORMED METHOD (Button Click --> Action?)-------------------------// public void actionPerformed(ActionEvent click) { Object source = click.getSource(); for(int i=1; i<=9; i++) { if(source == btnEmpty[i] && turn < 10) { btnEmptyClicked = true; if(!(turn % 2 == 0)) btnEmpty[i].setText("X"); else btnEmpty[i].setText("O"); btnEmpty[i].setEnabled(false); pnlPlayingField.requestFocus(); turn++; } } if(btnEmptyClicked) { checkWin(); btnEmptyClicked = false; } if(source == mnuNewGame || source == mnuInstruction || source == mnuAbout) { clearPanelSouth(); setDefaultLayout(); if(source == mnuNewGame) {//NewGame pnlTop.add(pnlNewGame); } else if(source == mnuInstruction || source == mnuAbout) { if(source == mnuInstruction) {// Instructions message = "Instructions:\n\n" + "Your goal is to be the first player to get 3 X's or O's in a\n" + "row. (horizontally, diagonally, or vertically)\n" + Player1 + ": X\n" + Player2 + ": O\n"; } else {//About message = "About:\n\n" + "Title: Tic-Tac-Toe\n" + "Creator: Blmaster\n" + "Version: " + VERSION + "\n"; } txtMessage.setText(message); pnlTop.add(txtMessage); } pnlMain.add(pnlTop); } else if(source == btn1v1 || source == btn1vCPU) { if(inGame) { option = askMessage("If you start a new game," + "your current game will be lost..." + "\n" + "Are you sure you want to continue?", "Quit Game?" ,JOptionPane.YES_NO_OPTION ); if(option == JOptionPane.YES_OPTION) inGame = false; } if(!inGame) { if(source == btn1v1) {// 1 v 1 Game btnContinue.setEnabled(true); new1v1Game(); } else {// 1 v CPU Game showMessage("Coming Soon!"); } } } else if(source == btnContinue) { checkTurn(); showGame(); } else if(source == btnSetName) { askUserForPlayerNames(); } else if(source == mnuExit) { option = askMessage("Are you sure you want to exit?", "Exit Game", JOptionPane.YES_NO_OPTION); if(option == JOptionPane.YES_OPTION) System.exit(0); } else if(source == btnTryAgain) { new1v1Game(); btnTryAgain.setEnabled(false); } else if(source == btnQuit) { inGame = false; btnContinue.setEnabled(false); goBack(); } pnlMain.setVisible(false); pnlMain.setVisible(true); } //-------------------END OF ACTION PERFORMED METHOD-------------------------// } /* Future Plans: -Add AI */ /* Changes: 2.0- changes below: bug fixes [Stable] 1.95- fixed bug: TryAgain Button takes over Status Label 1.9- added Label that shows Player 1 and Player 2 wins 1.8- removed Try Again pop-up. Added Try Again Button 1.7- removed Back Button. Added Continue Button 1.6- fixed bugs below... fixed bug: Same name for both players. fixed bug: Names updated in game if user changes. fixed bug: Names are null if user presses cancel. 1.5- added function to set Player Names. 1.4- program more efficient/faster. 1.35- fixed bugs, added turn status to status bar. 1.3- added Status bar with quit button during gameplay. 1.2- changed theme. 1.15- fixed bug: one win combo not working. 1.1- added play again function. 1.0- changes below: (problems gone!) [Stable] 0.9- added back button, added comments. 0.8- added dynamic win message. 0.7- added game function- game playable. 0.6- changed menu layout. 0.5- basic functions with menu and nice GUI. */ /* LAYOUT OF THE GAME: THE WINDOW: (pnlMenu/pnlMain) pnlMenu: (THE MENU) pnlMain: (pnlTop/pnlBottom) pnlTop: (pnlPlayingField/INSTRUCTIONS/ABOUT/NEW GAME) pnlBottom:(STATUS BAR/BACK BUTTON) /////////////////////////////////////////////////--------------| / pnlMenu / | / / | /////////////////////////////////////////////////-----| | / / | | / / | | / / | | / pnlTop / | | / / | |- MAIN WINDOW / / |- | / / |pnlMain | / / | | / / | | / / | | / / | | / / | | ///////////////////////////////////////////////// | | / pnlBottom / | | /////////////////////////////////////////////////-----|--------| */